Specifying joins is a key element of the QuerySpec API. It allows to specify joins with both EntityRelation objects, which are created using the generated code, as well as using extension methods. One can mix them to build joins.
Joins have to be specified inside a call to .From(). For DynamicQuery instances, this is straight forward. For EntityQuery<T> instances, this needs a construct called QueryTarget:
var q = qf.Customer .From(QueryTarget.InnerJoin(qf.Order).On(CustomerFields.CustomerId==OrderFields.OrderId))
QueryTarget is only needed for EntityQuery<T>
instances. DynamicQueries don't have a natural source, so in these cases,
one always has to specify the full left operand. Using QueryTarget
will lead to an error.
Note: |
Calling .From() multiple times will overwrite the From clause of the previous call, so specify all joins with one .From() call. |
The methods .InnerJoin(), .LeftJoin(), .RightJoin(), .FullJoin() and .CrossJoin() can be called inside a From() call on an EntityQuery<T> to join that entity query with a related element, which can be another query.
There are also overloads which accept an EntityRelation object. This can have the advantage where the user doesn't want to fill in the On clause, as that's already specified by the EntityRelation object. When an EntityRelation object is specified, the start entity has to match the T type of the EntityQuery<T>. The method called decides which JoinHint is used when adding the EntityRelation to the overall RelationCollection.
var qf = new QueryFactory(); // using a related element query and an On() clause. var q = qf.Employee .From(QueryTarget .LeftJoin(qf.Order).On(EmployeeFields.EmployeeId==OrderFields.EmployeeId)); // using an EntityRelation object var q2 = qf.Employee .From(QueryTarget.InnerJoin(EmployeeEntity.Relations.OrderEntityUsingEmployeeId));
With a DynamicQuery, QueryTarget can't be used. Calling the join
methods on a dynamic query like:
// Incorrect
var qf = new QueryFactory();
var q = qf.Create()
.From(QueryTarget.InnerJoin(qf.Order).On(some predicate));
This is not correct, although the api allows it, because a dynamic query
doesn't have a default source. Instead, use the From() method for dynamic queries:
// correct var qf = new QueryFactory(); var q = qf.Create() .From(qf.Customer .InnerJoin(qf.Order).On(CustomerFields.CustomerId==OrderFields.CustomerId));
For dynamic queries, to start a join with
an EntityRelation object and pass it to the From() method, use Joins.joinmethod. For example, to create an
Inner join using the join above but with entityrelation objects, one should
use:
// correct var qf = new QueryFactory(); var q = qf.Create() .From(Joins.Inner(CustomerEntity.Relations.OrderEntityUsingCustomerId));
As the .InnerJoin etc. methods work on an IJoinOperand object, this code
compiles:
// Incorrect
var qf = new QueryFactory();
// using a related element query and an On() clause.
var q = qf.Employee.LeftJoin(qf.Order).On(EmployeeFields.EmployeeId==OrderFields.EmployeeId));
However, this isn't correct as 'q' now is an InnerOuterJoin object, not a
query.